<template>
  <div id="app" :class="{loading: ajaxing}">
    <div class="backdrop" style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; top: 0; left: 0; z-index: 9999;" data-role="disable-mouse" v-show="ajaxing"></div>
     <m-fab
           position="bottom-right"
           :actions="fabActions"
           main-icon="build"
           main-tooltip="设置"
           size="small"
           :fixed-tooltip="true"
           @containChildDirectory="configToggle('containChildDirectory')"
           @multiTag="configToggle('multiTag')"
           ref="config"
        ></m-fab>
    <image-viewer
      :imageDB="db.image"
      :images="list"
      :index="viwer_index"
      :show="viewerShowing"
      @viewerHide="viewerShowing = false;"
      @addExtendInfo="showExtendInfoUpdator"
      @editExtendInfo="showExtendInfoUpdator"
      @editBaseInfo="renameImage"
      v-if="list.length"
    ></image-viewer>
    <div id="app-nav" class="d-lg-none">
      <nav class="navbar navbar-expand-lg navbar-light bg-light">
        <a class="navbar-brand" href="#"><img src="./assets/logo.png" alt="logo" class="img-fluid rounded-circle img-thumbnail logo"></a>
        <div class="p-2 align-middle text-right" style="flex-grow: 1;">
          <i class="material-icons btn-primary btn" data-toggle="tooltip" data-placement="top" title="上传图片至当前目录" v-tooltip @click="showUploader">cloud_upload</i>
        </div>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#directoryInNavBar" aria-controls="directoryInNavBar" aria-expanded="false" aria-label="Toggle navigation">
          <span class="navbar-toggler-icon"></span>
        </button>

        <directory-list
            class="collapse navbar-collapse"
            id="directoryInNavBar"
            :data="db.directory"
            :root="root"
            :active="path"
            @item-init="directoryInit"
            @item-click="updateUrlPath"
            @path-not-found="pathNotFound"
            @rename="renameDirectory"
            @create="createDirectory"
            @delete="removeDirectory"
            ref="directory1"
          ></directory-list>
      </nav>
      
    </div>
    <div class="container-fluid" id="app-content">
      <div class="row d-lg-none" style="height: 6rem;"></div>
      <div class="row">
        <div class="col-lg-4 d-none d-lg-block">
          <nav class="navbar navbar-light navbar-expand" id="state-bar">
            <a class="navbar-brand" href="#"><img src="./assets/logo.png" alt="logo" class="img-fluid rounded-circle img-thumbnail logo"></a>
            <div class="align-middle text-right p-2" style="flex-grow: 1;">
              <i class="material-icons btn-primary btn btn-sm" data-toggle="tooltip" data-placement="top" title="上传图片至当前目录" v-tooltip @click="showUploader">cloud_upload</i>
            </div>
          </nav>

          <directory-list
            id="directory-list"
            :data="db.directory"
            :root="root"
            :active="path"
            @item-init="directoryInit"
            @item-click="updateUrlPath"
            @path-not-found="pathNotFound"
            @rename="renameDirectory"
            @create="createDirectory"
            @delete="removeDirectory"
            ref="directory0"
          ></directory-list>
            
        </div>
        <div class="col-lg-8">
          <tag-list
            :data="db.tag"
            :activeTags="activeTags"
            :multiTag="config.multiTag"
            @remove-tag="deletaTag"
            @create-tag="createTag"
            @renameTag="renameTag"
          ></tag-list>
            
          <thumb-list
            id="thumb-list"
            :list="list"
            :spacing="10"
            @item-view="view"
            @removeFromTag="showTagPickerForRemove"
            @addToDirectory="showDirectoryAdder"
            @addToTag="showTagAdder"
            @remove="removeImagesFromDirectory"
            @rename="renameImage"
          ></thumb-list>
          
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import Vue from 'vue'
import $ from 'jquery'
import 'bootstrap/dist/css/bootstrap.min.css';
import 'bootstrap/dist/js/bootstrap.min.js';
import _ from 'lodash'


import mFab from './components/m-fab'
import thumbList from './components/thumb-list.vue'
import imageViewer from './components/image-viewer.vue'
import tagList from './components/tag-list'
import directoryList from './components/directory-list'
import directoryPicker from './components/directory-picker'
import tagPicker from './components/tag-picker'
import namePicker from './components/name-picker'
import uploader from './components/uploader'
import extendInfoUpdator from './components/extend-info-updator'
import imgRenameModal from './components/image-rename-modal-body'


import path from 'path'

import VModal from 'vue-js-modal'

Vue.use(VModal,{ dynamic: true, injectModalsContainer: true })

import Scrollbar from 'smooth-scrollbar';
import OverscrollPlugin from 'smooth-scrollbar/plugins/overscroll';
import autoX from './plugin/smooth-scrollbar-autoX';
Scrollbar.use(autoX, OverscrollPlugin);
OverscrollPlugin.defaultOptions.effect = 'glow';

Vue.directive('tooltip', {
  bind: function(el, binding) {
    $(el).tooltip()
  },
  update: function(el, binding) {
    $(el)
      .tooltip('dispose')
      .tooltip()
  },
  unbind: function(el, binding) {
    $(el).tooltip('dispose');
  }
});

export default {
  name: 'App',
  components: { thumbList, imageViewer, mFab, directoryList, tagList },
  props: {
    db: {
      type: Object,
      required: true
    },
    root: {
      type: String,
      required: true
    },
    path: {
      type: String,
      required: true
    }
  },
  data() {
    var vm = this;
    return {
      moveType: "",
      chosedItem: [],
      ajaxing: false,
      activeDirectory: null,
      activeTags: [],
      viwer_index: 0,
      viewerShowing: false,
      config: {
        containChildDirectory: false,
        multiTag: false
      },
      activeState: {
        containChildDirectory: {
          icon: 'check_box',
          tooltip: '包含子目录',
        },
        multiTag: {
          icon: 'check_box',
          tooltip: '多标签筛选'
        }
      },
      unActiveState: {
        containChildDirectory: {
          icon: 'check_box_outline_blank',
          tooltip: '包含子目录',
        },
        multiTag: {
          icon: 'check_box_outline_blank',
          tooltip: '多标签筛选'
        }
      },
      postHandler: {
        before: function() {
          vm.ajaxing = true;
        },
        after: function() {
          vm.ajaxing = false;
        }
      }
    }
  },
  computed: {
    fabActions() {
      var actions = [], config = this.config;
      for (var i in config) {
        var target = config[i] ? this.activeState[i] : this.unActiveState[i];
        actions.push(
          Object.assign({
            name: i,
          }, target)
        );
      }
      return actions;
    },
    list() {
      if (!this.activeDirectory) {
        return [];
      }
      var images = this.db.image;
      var getImageObj = function(dItem) {
        return dItem.ref.content.map(x => images[x]).filter(x => x);
      };
      var obj = this.activeDirectory.ref,
          arr = getImageObj(this.activeDirectory);
      if (this.config.containChildDirectory) {
        var queue = this.activeDirectory.children.slice();
        while (queue.length) {
          var cur = queue.shift();
          // console.log('cur', cur, cur.children.slice());
          arr.push.apply(arr, getImageObj(cur));
          queue.push.apply(queue, cur.children.slice());
        }
      }

      arr = _.uniqBy(arr, '_id');
      var tagDB = this.db.tag;
      this.activeTags.forEach((tag_id) => {
        arr = arr.filter(x => tagDB[tag_id].content.includes(x._id));
      });
      return arr;
    }
  },
  methods: {
    pathNotFound: _.debounce(function() {
      console.log('pathNotFound', this.path);
      this.$emit('pathNotFound', path.join(this.path, '../') || '/', this.path);
    }, 300),
    _updatePath(path) {
      var vm = this;
      vm.$nextTick(() => {
        vm.$emit('directoryChange', {
          path
        });
      })
    },
    _updatePathByReplace(path) {
      var vm = this;
      vm.$nextTick(function() {
        vm.$emit('directoryReplace', {
          path
        });
      })
    },
    deletaTag(tag) {
      var vm = this;
      vm.db.getDB().ajax
        .deleteTag(tag._id);
    },
    createTag() {
      var vm = this;
      vm.$modal.show(namePicker, {
        value: "",
        title: "创建标签",
        callback(name) {
          var that = this;
          that.waiting = true;
          vm.db.getDB().ajax
            .createTag(name)
            .always(function() {
              that.waiting = false;
            })
            .done(function() {
              that.$emit('close');
            })
            .fail(() => {that.error = true;});
        }
      }, {
        name: 'dynamic-modal',
        resizable: false,
        adaptive: true,
        draggable: false,
        clickToClose: false,
        scrollable: false,
        height: "auto"
      });
    },
    renameTag(_id) {
      var vm = this;
      vm.$modal.show(namePicker, {
        value: vm.db.tag[_id].name,
        title: "重命名标签",
        callback(name) {
          var that = this;
          that.waiting = true;
          vm.db.getDB().ajax
            .renameTag(_id, name)
            .always(function() {
              that.waiting = false;
            })
            .done(function() {
              that.$emit('close');
            })
            .fail(() => {that.error = true;});
        }
      }, {
        name: 'dynamic-modal',
        resizable: false,
        adaptive: true,
        draggable: false,
        clickToClose: false,
        scrollable: false,
        height: "auto"
      });
    },
    createDirectory({directory}){
      var vm = this;
      vm.$modal.show(namePicker, {
        value: "",
        title: "创建目录",
        callback(name) {
          var that = this;
          that.waiting = true;
          vm.db.getDB().ajax
            .createDirectory(directory._id, name)
            .always(function() {
              that.waiting = false;
            })
            .done(function(entity) {
              that.$emit('close');
              vm._updatePath(path.join(vm.path, entity.name))
            })
            .fail(() => {that.error = true;});
        }
      }, {
        name: 'dynamic-modal',
        resizable: false,
        adaptive: true,
        draggable: false,
        clickToClose: false,
        scrollable: false,
        height: "auto"
      });
    },
    renameDirectory({directory}){
      var vm = this;
      vm.$modal.show(namePicker, {
        value: directory.name,
        title: "重命名目录",
        callback(name) {
          var that = this;
          that.waiting = true;
          vm.db.getDB().ajax
            .renameDirectory(directory._id, name)
            .always(function() {
              that.waiting = false;
            })
            .done(function(entity) {
              that.$emit('close');
              vm._updatePathByReplace(path.join(vm.path, '../', entity.name));
            })
            .fail(() => {that.error = true;});
        }
      }, {
        name: 'dynamic-modal',
        resizable: false,
        adaptive: true,
        draggable: false,
        clickToClose: false,
        scrollable: false,
        height: "auto"
      });
    },
    removeDirectory({directory}){
      var vm = this,
        parent_path = path.join(vm.path, '../'),
        parent = vm.$refs.directory0.getDirectoryObj(parent_path);
      if (!parent) {
        return;
      }
      vm.db.getDB().ajax
        .removeDirectoryFromParent(parent._id, directory._id)
        .done(function(entity) {
          vm._updatePathByReplace(parent_path)
        });
        
    },
    addImagesToTags([...image_ids], [...tag_ids], notifier) {
      var vm = this, db = vm.db.getDB();
      var length = tag_ids.length;
      var wait = $.Deferred();
      db.autoFlush = !length;
      tag_ids.forEach((_id, i) => {
        db.ajax
          .addImagesToTag(image_ids, _id)
          .then(function() {
            notifier && notifier.notify(_id, i);
            --length;
            if (!length) {
              db.autoFlush = true;
              db.flush();
              wait.resolve();
            }
          }, function() {
            notifier && notifier.notify(_id, i);
            --length;
          });
      });
      return wait.promise();
    },
    addImagesToDirectorys([...image_ids], [...directory_ids], notifier) {
      var vm = this, db = vm.db.getDB();
      var length = directory_ids.length;
      var wait = $.Deferred();
      db.autoFlush = !length;
      directory_ids.forEach((_id, i) => {
        db.ajax
          .addImagesToDirectory(image_ids, _id)
          .then(function() {
            notifier && notifier.notify(_id, i);
            --length;
            if (!length) {
              db.autoFlush = true;
              db.flush();
              wait.resolve();
            }
          }, function() {
            notifier && notifier.notify(_id, i);
            --length;
          });
      });
      return wait.promise();
    },
    removeImagesFromTags([...image_ids], [...tag_ids], notifier) {
      var vm = this, db = vm.db.getDB();
      var length = tag_ids.length;
      var wait = $.Deferred();
      db.autoFlush = !length;
      tag_ids.forEach((_id, i) => {
        db.ajax
          .removeImagesFromTag(image_ids, _id)
          .then(function() {
            notifier && notifier.notify(_id, i);
            --length;
            if (!length) {
              db.autoFlush = true;
              db.flush();
              wait.resolve();
            }
          }, function() {
            notifier && notifier.notify(_id, i);
            --length;
          });
      });
      return wait.promise();
    },
    directoryInit(vn, item) {
      this.activeDirectory = item;
    },
    updateUrlPath(item) {
      var prev = this.activeDirectory,
          change = !prev || (prev.ref != item.ref);
      if (change) {
        this.activeDirectory = item;
      }
      if (!prev) {
        this.$emit('directoryInit', item);
      } else if (change)  {
        this.$emit('directoryChange', item, prev);
      }
    },
    configToggle(field) {
      var vm = this;
      (field in this.config) && (this.config[field] = !this.config[field]);
    },
    view: function(img, index) {
      this.viwer_index = index;
      this.viewerShowing = true;
    },
    removeImagesFromDirectory([...image_objs]) {
      var image_ids = image_objs.map(x => x._id);
      var _id = this.activeDirectory.ref._id;
      var vm = this, db = vm.db.getDB();
      return db.ajax
          .removeImagesFromDirectory(image_ids, _id);
    },
    showDirectoryAdder(images) {
      var vm = this;
      vm.moveType = "directory";
      vm.chosedItem = images;
      vm.$modal.show(directoryPicker, {
        data: vm.db.directory,
        root: vm.root,
        active: vm.path,
        confirmHandler:  function(arr) {
          var md = this.notifier;
          vm.addImagesToDirectorys(images.map(x=>x._id), _.uniq(arr.map(x => x.ref._id)), md)
          .done(md.resolve);
        },
        title: "添加到分类"
      }, {
        name: 'dynamic-modal',
        resizable: false,
        adaptive: false,
        draggable: false,
        clickToClose: false,
        scrollable: false,
        height: "auto"
      })
    },
    showTagAdder(images) {
      var vm = this;
      vm.moveType = "tag";
      vm.chosedItem = images;
      vm.$modal.show(tagPicker, {
        data: vm.db.tag,
        confirmHandler:  function(arr) {
          var md = this.notifier;
          vm.addImagesToTags(images.map(x=>x._id), _.uniq(arr), md)
          .done(md.resolve);
        },
        title: "添加到标签"
      }, {
        name: 'dynamic-modal',
        resizable: false,
        adaptive: false,
        draggable: false,
        clickToClose: false,
        scrollable: false,
        height: "auto"
      })
    },
    showTagPickerForRemove(images) {
      var vm = this;
      vm.moveType = "tag";
      vm.chosedItem = images;
      vm.$modal.show(tagPicker, {
        data: vm.db.tag,
        confirmHandler:  function(arr) {
          var md = this.notifier;
          vm.removeImagesFromTags(images.map(x=>x._id), _.uniq(arr), md)
          .done(md.resolve);
        },
        title: "从标签中移除"
      }, {
        name: 'dynamic-modal',
        resizable: false,
        adaptive: false,
        draggable: false,
        clickToClose: false,
        scrollable: false,
        height: "auto"
      })
    },
    showUploader() {
      var vm = this,
          db = vm.db.getDB();
      vm.$modal.show(uploader, {
        directory: vm.activeDirectory.ref._id,
        callback: function(files) {
          var resArr = files.map(file => file.response);
          var directoryObjs = [];
          resArr.forEach(res => {
            res.images.forEach(image => {
              db.update(db.image, {name: 'create', obj: image});
            })
            // 多线程并发上传导致读写不一致问题，需根据__v属性辨识最新版本
            directoryObjs.push(res.directory);
          })
          directoryObjs.length
          && db.update(db.directory, {name: 'merge', obj: directoryObjs.sort((a, b) => b.__v - a.__v)[0]});
          vm.$nextTick(function() {
            var dls = [vm.$refs.directory0, vm.$refs.directory1];
            dls.forEach(x => x.initialActive());
          })
        }
      }, {
        name: 'dynamic-modal',
        resizable: false,
        adaptive: false,
        draggable: false,
        clickToClose: false,
        scrollable: false,
        width: "800px",
        height: "auto"
      })
    },
    showExtendInfoUpdator(image, info) {
      var vm = this,
          db = vm.db.getDB();
      var handler = function(method, autoClose) {
        return function(img, obj) {
          var that = this;
          that.waiting = true;
          method(img._id, obj)
          .always(() => {
            that.resolved = true;
            that.waiting = false;
          })
          .done(function() {
            that.succeed = true;
            if (autoClose) {
              that.$emit('close');
            }
          })
          .fail(function() {
            that.succeed = false;
          });
        }
      };
      vm.$modal.show(extendInfoUpdator, {
        image: image,
        info: info,
        onremove: function(img, obj) {
          var that = this;
          that.waiting = true;
          db.ajax.removeExtendInfo(img._id, obj)
          .always(() => {
            that.waiting = false;
          })
          .done(() => {
            that.$emit('close');
          })
        },
        onupdate: handler(db.ajax.updateExtendInfo, true),
        oncreate: handler(db.ajax.addExtendInfo)
      }, {
        name: 'dynamic-modal',
        resizable: false,
        adaptive: true,
        draggable: false,
        clickToClose: false,
        scrollable: false,
        height: "auto"
      });
    },
    renameImage(image) {
      var vm = this;
      vm.$modal.show(imgRenameModal, {
        image,
        callback(name) {
          var that = this;
          that.waiting = true;
          vm.db.getDB().ajax
            .renameImage(image._id, name)
            .always(function() {
              that.waiting = false;
            })
            .done(function() {
              that.$emit('close');
            })
            .fail(() => {that.error = true;});
        }
      }, {
        name: 'dynamic-modal',
        resizable: false,
        adaptive: true,
        draggable: false,
        clickToClose: false,
        scrollable: false,
        height: "auto"
      });
    }
  },
  watch: {
    "db.directory": function() {
      // console.log('db change');
    }
  },
  created() {
    var vm = this;
    for (var i in vm.postHandler) {
      $.post[i].add(vm.postHandler[i]);
    }
  },
  mounted() {
    
  },
  destroyed() {
    var vm = this;
    for (var i in vm.postHandler) {
      $.post[i].remove(vm.postHandler[i]);
    }
  }
}

</script>
<style type="text/css">
.scrollbar-track-x,
.scrollbar-track-x>.scrollbar-thumb {
    height: 5px !important;
}
.scrollbar-track-y,
.scrollbar-track-y>.scrollbar-thumb {
    width: 5px !important;
}
</style>

<style>

#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  box-sizing: border-box;
  position: relative;
  overflow: hidden;
  user-select: none;
}
#app-content {
  width: 100vw;
  height: 100vh;
  overflow: hidden;
}


#state-bar {
  padding: .5rem 1px;
}

#app-nav {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  box-shadow: 0 1px 3px gray;
  z-index: 1000;
}

#state-bar .logo,
#app-nav .logo {
  max-height: 4rem;
}

#thumb-list .list-container {
  width: 100%;
  height: 100vh;
  overflow: hidden;
}

#thumb-list .list-container .list {
  box-sizing: content-box;
  padding-bottom: 14rem;
  margin-top: .5rem;
}

#directory-list .directory-container,
#directoryInNavBar .directory-container {
  max-height: 100vh;
  overflow: hidden;
  line-height: 0;
}

#directory-list .list {
  padding-bottom: 7rem;
}

#directoryInNavBar {
  box-shadow: 0 -1px 8px -7px gray;
}

#directoryInNavBar .list {
  padding-bottom: 5rem;
}


@keyframes spread {
  0% {
    box-shadow: 0 0 1px black, 0 0 0px white;
  }
  100% {
    box-shadow: 0 0 10px #007bff, 0 0 10px white;
  }
}

#app.loading .logo {
  -webkit-animation: spread 1s ease 0s infinite alternate;
     -moz-animation: spread 1s ease 0s infinite alternate;
      -ms-animation: spread 1s ease 0s infinite alternate;
       -o-animation: spread 1s ease 0s infinite alternate;
          animation: spread 1s ease 0s infinite alternate;
}

.v--modal-overlay {
  z-index: 1017;
}

/* img[lazy=error] {
  box-shadow: inset 0 0 6px 1px #9E9E9E;
} */

</style>
